home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / STUTTGART / LANG / FORTH / FORTHMAC / OLD / DOCS / !Forthmacs.docs.ascii.armastut < prev    next >
Encoding:
Text File  |  1996-06-15  |  18.1 KB  |  477 lines

  1.  
  2. Assembler Tutorial
  3. ******************
  4.  
  5. This chapter explains how to use the RISC OS Forthmacs ARM assembler 
  6. in order to create short machine language code sequences.  This 
  7. chapter is a companion to the "ARM Assembler" chapter.  That chapter 
  8. describes the syntax of individual assembly language instructions.  
  9. This chapter addresses "higher level" issues, such as how to begin and 
  10. end the assembly process and how to communicate arguments and result 
  11. between Forth and assembly language.  
  12.  
  13.  
  14. Motivation
  15. ==========
  16.  
  17. For nearly all debugging jobs, writing assembly language is 
  18. unnecessary.  Test loops can be usually be written more quickly and 
  19. easily in high-level Forth, and will execute quickly enough to get the 
  20. job done.  
  21.  
  22. However, in some cases the ultimate in speed is needed for certain 
  23. critical operations, and assembly language may be the best way to go.  
  24. In other cases, very specific combinations of machine instructions may 
  25. exhibit problem behavior, and those combinations may need to be 
  26. reproduced.  Finally, some maintainers of the RISC OS Forthmacs system 
  27. software itself may need to understand the assembler.  
  28.  
  29.  
  30. Assumptions
  31. ===========
  32.  
  33. The chapter assumes that you already understand the ARM instruction 
  34. set, including such issues as processor modes, interrupts and 
  35. registers sets.  If not, you should first study a ARM reference, such 
  36. as the manual published by the chip manufacturer.  
  37.  
  38. Please note the sysntax of this ARM assembler, it uses - as most Forth 
  39. assemblers - the operand first - operator last syntax.  
  40.  
  41.  
  42. Example: a simple "code word"
  43. =============================
  44.  
  45. Here is a very simple assembly language program.  It adds "1" to the 
  46. contents of a register then returns to the Forth interpreter.  This 
  47. register r10 holds the top of stack value.  
  48.  
  49.     code addone  ( n -- n+1 )
  50.     r10 r10  1 # add
  51.     c;
  52.  
  53. To execute it and display the result, you would type, for example, 
  54.  
  55.     5 addone .
  56.  
  57. Here's what is happening, line by line: 
  58.  
  59.     code addone  ( n -- n+1 )
  60.  
  61. CODE is a "defining word"; it creates a new command which can be 
  62. executed by typing its name.  The name of the new command in this case 
  63. is ADDONE .  The name could have been anything; I have chosen the name 
  64. ADDONE because it describes the action of the program.  You may 
  65. already be familiar with another Forth defining word " : or COLON ". 
  66. ":" also creates a new command; the difference between CODE and ":" is 
  67. that ":" creates a new command whose behavior is described by a 
  68. sequence of other Forth commands, whereas CODE creates a new command 
  69. whose behavior is described by a sequence of assembly language 
  70. instructions.  After CODE creates the new command, it starts the 
  71. assembler so that assembly language instructions may be entered.  
  72.  
  73. The stuff inside the parentheses is a comment; this particular comment 
  74. indicates that the new command expects one argument ("n") on the stack 
  75. before the word is executed, and after the command is executed, one 
  76. result ("n+1") is left on the stack.  The comment is optional, but its 
  77. inclusion is strongly recommended.  
  78.  
  79.     r10 r10  1 # add
  80.  
  81. This is the assembly language instruction which defines the action of 
  82. the new command.  As you will recall from the "ARM Assembler" chapter, 
  83. the RISC OS Forthmacs assembler syntax has the destination register 
  84. first, followed by the source operand(s), followed by the operation 
  85. name.  So, in this case, the source operands are the global register 
  86. r10 and the immediate number 1, the destination operand is the global 
  87. register r10, and the operation is add, i.e.  1 is added to the 
  88. contents of register r10, and the result is placed back in register 
  89. r10.  
  90.  
  91.     c;
  92.  
  93. C; terminates the definition of a code definition.  At the end of the 
  94. instructions you have assembled, C; automatically appends one machine 
  95. instruction, its effect is to return to Forth after the user-specified 
  96. instructions have been executed.  
  97.  
  98.     5 addone .
  99.  
  100. In order to invoke the new command, we enter the number 5 on the Forth 
  101. stack, type the name of the command ADDONE , and then display the 
  102. result by typing the print command "." .  
  103.  
  104. Perhaps you now wonder how the number got off the Forth stack and into 
  105. the register r10, and afterwards how the number got out of r10 and 
  106. back onto the Forth stack.  The answer is simple: the top element of 
  107. the Forth stack is always (!) kept in r10 , so no movement was 
  108. necessary.  That is why I chose r10 for the register in this example.  
  109.  
  110.  
  111. Register Usage in Forth
  112. =======================
  113.  
  114. To use the assembler effectively, you need to know which registers are 
  115. available for use, and which of them must be left alone.  Here are the 
  116. rules: 
  117.  
  118. r8, r9, r12, and r14 are used internally by the Forth interpreter or 
  119. operating system, their values must be left alone (otherwise the 
  120. system will crash).  
  121.  
  122. r10 contains the top of the Forth stack.  It is used for passing 
  123. arguments and results back and forth between Forth and assembly 
  124. language.  
  125.  
  126. r13 contains a pointer to a memory area containing the rest of the 
  127. Forth stack (all elements other than the topmost one).  That stack 
  128. area is used for extra arguments and results.  The section entitled 
  129. "Stack Usage" tells you more about managing the stack area.  
  130.  
  131. r0 - r6 may be used freely within assembly language code sequences.  
  132. Forth does not depend on the contents of these registers.  However, 
  133. some Forth commands DO use these registers as scratch registers, so 
  134. your code should not attempt to keep important values in these 
  135. registers from one time to the next.  While your code is being 
  136. executed, Forth will not change the contents of any of these 
  137. registers, so you can depend on them for the duration of your assembly 
  138. language sequence.  When your code finishes and returns to Forth, the 
  139. next time that you execute your code the register values may have 
  140. changed.  
  141.  
  142. You can find more information about this subject in the "ARM 
  143. Assembler" and "Forthmacs Implementation" chapters.  
  144.  
  145. While your machine code is executing, it will run at the full speed of 
  146. the system, without any interference or overhead imposed by 
  147. RISC OS Forthmacs.  RISC OS Forthmacs does not itself use interrupts, 
  148. so the processor will execute exactly the sequence of instructions 
  149. which you have coded.  It is possible that other software in the 
  150. system may have set up some interrupts, but that is beyond the control 
  151. of RISC OS Forthmacs.  
  152.  
  153.  
  154. Disassembler
  155. ============
  156.  
  157. The RISC OS Forthmacs disassembler may be used to review the assembly 
  158. language you have created: 
  159.  
  160.     see addone
  161.  
  162. The result will look something like this: 
  163.     code addone
  164.     (  1e878 )  add     r10,r10,#1
  165.     (  1e87c )  ldr     pc,[r8],#4
  166.  
  167.  
  168. The numbers along the left hand side are the addresses at which the 
  169. various instructions appear.  The addresses shown here will almost 
  170. certainly be different from the addresses that you see.  
  171.  
  172. You will notice that even though our example contained only one 
  173. assembly language instruction the disassembler shows 1 extra 
  174. instruction.  This extra instruction was automatically assembled by 
  175. the C; command.  Their purpose is to return control to Forth after the 
  176. assembly language sequence has finished its execution (this is called 
  177. the NEXT instruction).  
  178.  
  179. The SEE command reads the name of a Forth command (in this case 
  180. "addone"), determines what type of command it is (in this case "code 
  181. ", meaning that the command's behavior was defined by the assembler), 
  182. and then displays a reconstruction of the source code for that 
  183. command.  SEE also works for "colon" definitions, whose behaviour is 
  184. defined in Forth instead of in assembly language.  For an example of 
  185. this, type "see find".  
  186.  
  187. Many of the normal Forth commands are defined in assembly language, 
  188. and SEE can be used to look at how they are implemented.  For example, 
  189. type "see @" to see how the Forth "@" operator works (pronounced 
  190. fetch, this operator takes an address from the top of the stack, reads 
  191. the 32-bit contents of that address, and puts those contents back on 
  192. top of the stack).  You should try this right now and make sure you 
  193. understand how it works.  Note that the last instructions of "@" is 
  194. exactly the same as the last instruction of "addone".  Every code 
  195. definition in RISC OS Forthmacs ends with these same three 
  196. instructions.  
  197.  
  198. SEE automatically locates the address where the code for particular 
  199. command begins.  That address was allocated by CODE when the new 
  200. command was defined.  The disassembler can also be used to inspect 
  201. machine code beginning at arbitrary addresses, not only that code 
  202. which is created by CODE .  Suppose that you know there is some code 
  203. starting at address 100000 and you wish to look at it: 
  204.  
  205.     100000 dis
  206.  
  207. On your system, this example probably won't work exactly as shown 
  208. because your system may not have any code at address 100000 (in fact, 
  209. it may not even have any memory there.  The main point, though, is 
  210. that you type the address of the code you wish to disassemble, 
  211. followed by "dis".  
  212.  
  213. The disassembler will continue until it reaches a "definition ending" 
  214. instruction, or until you stop it by typing the character "q", for 
  215. "quit".  It will also pause at the end of a screen and prompt you for 
  216. a continuation character.  
  217.  
  218. After the disassembler has stopped, you can make it continue where it 
  219. left off by typing +DIS 
  220.  
  221.  
  222. Setting the Starting Address
  223. ============================
  224.  
  225. In most cases, you won't need to specify a starting address for the 
  226. code you assemble.  When you use the CODE defining word to begin 
  227. assembling, RISC OS Forthmacs will find some appropriate memory for 
  228. you and assemble your code there ( at HERE). You can then locate the 
  229. memory RISC OS Forthmacs has chosen by using the SEE command to 
  230. disassemble the code, looking at the addresses displayed alongside the 
  231. machine instructions.  
  232.  
  233. If you really need to assemble at a specific address, you can do so as 
  234. follows (Note: in nearly all cases, this technique is unnecessary; 
  235. very rarely does it matter where exactly you locate a bit of code, and 
  236. allowing RISC OS Forthmacs to allocate the memory for you is 
  237. sufficient and convenient).  
  238.  
  239. Set the DP by 
  240.     here @
  241.     your-adr dp !
  242.     code demo
  243.            ...... c;
  244.     here !
  245.  
  246.  
  247. Conditional branches
  248. ====================
  249.  
  250. In order to implement conditional operations and loops, most 
  251. assemblers provide branch instructions and labels.  RISC OS Forthmacs 
  252. has branches and labels too, but it also has a much better way, which 
  253. eliminates most of the troublesome aspects of coding conditionals and 
  254. loops in assembly language.  The RISC OS Forthmacs way is called 
  255. "structured conditionals".  For example, suppose we want to test a 
  256. condition and execute some code only if the condition is true.  
  257. Specifically, we want to compare r0 and r1, and execute some code only 
  258. if r0 is less than r1 .  
  259.  
  260.     Traditional assembler:
  261.     
  262.                  cmp   r0, r1
  263.                  bge   temp
  264.                     ..some code we want to conditionally execute
  265.          temp:
  266.  
  267.          Forthmacs assembler with structured conditionals:
  268.     
  269.                  r0 r1  cmp
  270.                  < if
  271.                     ..some code we want to conditionally execute..
  272.                  then
  273.  
  274. As you can see, RISC OS Forthmacs eliminates the need to mentally 
  275. reverse the sense of the comparison, eliminates the need to invent and 
  276. keep track of label names, and uses conventional mathematical 
  277. comparison symbols (e.g.  "<"), rather then alphabetic mnemonics.  The 
  278. complete set of comparison symbols is given in the "ARM Assembler" 
  279. chapter.  
  280.  
  281. The "if ..  then" construct can also include an "else" clause: 
  282.  
  283.                  r0 r1 s cmp  \ the s is optional
  284.                  < if
  285.                     ..code to execute if r0 < r1..
  286.                  else
  287.                     ..code to execute if r0 >= r1..
  288.                  then
  289.  
  290. Of course, the assembler actually generates conditional branch 
  291. instructions because that's what the hardware supports directly, but 
  292. RISC OS Forthmacs takes care of the "bookkeeping" for you.  
  293.  
  294. Another way would be to use the conditional instructions offered by 
  295. the ARM cpu.  
  296.  
  297.                  r0  r1 cmp
  298.                  xx xx  lt xxx
  299.                  yy yy  ge xxx
  300.  
  301.  
  302.  
  303. Delayed Branches
  304. ================
  305.  
  306. ARM doesn't uses delayed branches at all, so don't worry.  
  307.  
  308.  
  309. Loops
  310. =====
  311.  
  312. RISC OS Forthmacs structured conditionals also have features for 
  313. easily creating loops.  Here is a loop which executes forever: 
  314.  
  315.                  Source                  Generates
  316.     
  317.                  begin                   Label1:
  318.                     top  r0 ) ldr              ldr  r10,[r10,#0]
  319.                  again                         b Label1
  320.  
  321. This code assumes that the r10 register (top of stack, remember?) 
  322. contains the address of a memory location, and the contents of that 
  323. memory location is continuously read into the r0 register.  This is an 
  324. infinite loop; it won't stop until the system is reset, or power 
  325. cycled, or externally interrupted in some way.  
  326.  
  327. Suppose we want the loop to execute 9 times then quit: 
  328.  
  329.   r1  9 #    mov
  330.   begin
  331.      r0   top ) ldr
  332.      r1   r1 1 # s sub
  333.   <= until
  334.  
  335.  
  336. We continue to loop "until" r1 <= 1 .  
  337.  
  338. Finally, here's an example where we perform a test at the top of the 
  339. loop rather than at the bottom, illustrating "while": 
  340.  
  341.   r1  9 #     mov
  342.   begin
  343.       r1 r1 1 s sub
  344.   > while
  345.       r0  top ) ldr
  346.   repeat
  347.  
  348.  
  349. This loop continues to execute "while" r11 > 1, and the "repeat" sends 
  350. it back to the "begin".  
  351.  
  352. Structured conditionals and loops nest in the expected manner, to an 
  353. arbitrary depth.  For instance, a "begin ..  until" can be completely 
  354. contained within an "if ..  then", which itself may be contained 
  355. within a "begin ..  while ..  repeat".  
  356.  
  357.  
  358. Scope Loops - Assembler vs. Forth
  359. =================================
  360.  
  361. You can use assembly language for creating scope loops, but it is 
  362. usually preferable to write them in Forth, because the Forth version 
  363. is usually easier to write, easier to read, and easier to debug.  The 
  364. one advantage of an assembly language loop is that it is tighter.  
  365. However this rarely matters.  For comparison, suppose that you want to 
  366. continually read location 1000 so that you can observe the action on 
  367. an oscilloscope.  This is how you would do it in assembly language: 
  368.  
  369.          code test
  370.          r0 th 1000 # mov
  371.             begin
  372.               r1  r0 ) ldr
  373.             again
  374.  
  375. Here's how you would do the same thing in Forth: 
  376.  
  377.     begin  1000 @ drop  again
  378.  
  379. Additionally, the Forth version may be easily adapted to stop looping 
  380. as soon as a key is typed: 
  381.  
  382.     begin  1000 @ drop  key? until
  383.  
  384. More importantly, many of today's complicated chips require fairly 
  385. extensive initialization sequences in order to configure them to the 
  386. correct operating mode.  Such code is much easier to write and debug 
  387. in Forth, because you can "try things out" by typing commands at the 
  388. keyboard, the looking at the registers to see what happened.  
  389.  
  390. A set of simple Forth commands sufficient to do most hardware 
  391. debugging jobs can easily be described on a single page, and many 
  392. engineers and technicians have learned enough Forth in 30 minutes to 
  393. be able to write sophisticated diagnostics for complicated hardware.  
  394.  
  395.  
  396. Stack Usage
  397. ===========
  398.  
  399. A previous example has shown how to access the top element on the 
  400. stack which is stored in r10.  Things get a little more complicated if 
  401. more than 1 stack argument is needed.  Remember that the top of the 
  402. stack is stored in r10, and subsequent stack items are stored in a 
  403. memory area whose address is contained in r13.  For convenience, the 
  404. assembler provides alternate names for r10 and r13, reflecting the use 
  405. of these registers for the stack.  r10 is also known as TOP (Top of 
  406. Stack), and r13 is also known as SP (Stack Pointer).  
  407.  
  408. The basic rules for the Forth stack are: 
  409.  
  410. a) Upon entry to a CODE definition (assembly language), the top of the 
  411. stack is contained in TOP. The next item on the stack is in the memory 
  412. location whose address is contained in SP. The item after that is in 
  413. memory at SP+4 , the next at SP+8 , etc.  Note that successive stack 
  414. items are 4 bytes (32-bits) apart.  
  415.  
  416. b) A definition may modify the stack contents, and upon exit from the 
  417. definition the new top of the stack should be in TOP, and the next 
  418. item should be in memory at that address contained in SP. 
  419.  
  420. c) Assembly code should not access memory at negative offsets from SP. 
  421. This restriction safeguards against problems in an interrupt-driven 
  422. environment, in case the same stack happens to be used for interrupt 
  423. handlers.  
  424.  
  425. If items are removed from the stack by a code definition, care must be 
  426. taken to make sure the correct top of stack value is left in TOP. Also 
  427. remember that the RISC OS Forthmacs assembler provides macros to 
  428. assist in managing the stack.  Here are some examples; study them 
  429. carefully: 
  430.  
  431. code and        (s n1 n2 -- n3 )
  432.                 r0      sp      pop
  433.                 top     top     r0 and c;
  434. code min        (s n1 n2 -- n1|n2 )
  435.                 r0      sp      pop
  436.                 top     r0      cmp
  437.                 top     r0      gt mov c;
  438. code drop       (s n1 n2 -- n1 )
  439.                 top     sp      pop c;
  440. code dup        (s n1 -- n1 n1 )
  441.                 top     sp      push c;
  442. code 1+         (s n -- n+1 )    top 1     incr c;
  443. code @          (s a_adr -- n )
  444.                 top     top )   ldr c;
  445. \ a somewhat optimized fill
  446. code fill       (s adr cnt char -- )
  447.                 r2      top     top  8 #lsl orr
  448.                 r0 r1 top 3 sp ia!  ldm \ r0-cnt r1-adr r2-data
  449.                 r0      4 #     cmp
  450.   gt if
  451.         begin   r3      r1      3 # s and
  452.                 r0      1       ne decr
  453.                 r2      r1 byte )+ ne str
  454.         eq until
  455.                 r0      8       s decr
  456.                 r2      r2      r2  10 #lsl orr
  457.                 r3      r2      mov
  458.         begin   r2 r3 2 r1 ia!  ge stm
  459.                 r0      8       ge s decr
  460.         lt until
  461.                 r0      4       s incr
  462.                 r2      r1 )+   ge str
  463.                 r0      4       lt decr
  464.   then
  465.         begin   r0      1       s decr
  466.                 r2      r1 byte )+ ge str
  467.         lt until c;
  468. code >name      \ (s cfa -- nfa )
  469.                 top     1       decr    \ skip flag byte
  470.         begin   r0      top byte -( ldr
  471.                 r0      0 #     cmp
  472.         ne until
  473.         begin   r0      top byte -( ldr
  474.                 r0      20 #    cmp
  475.         lt until c;
  476.  
  477.